package ch.simas.nbtostring.builder;

import com.sun.source.tree.BlockTree;
import com.sun.source.tree.StatementTree;
import java.util.ArrayList;
import java.util.List;
import javax.lang.model.element.Element;
import org.netbeans.api.java.source.TreeMaker;
import org.netbeans.api.java.source.WorkingCopy;

/**
 * Abstract class to avoid code duplication. Current implementors are {@link StringBufferToStringBuilder} and
 * {@link StringBuilderToStringBuilder}
 * @author cperv
 * @since 0.3.0
 */
abstract class AbstractBuilderBufferBuilder extends ToStringBuilder {

    // TODO: think about to calculate a rough initial size - each append forces a resize of the StringBuilder, which
    // of course is time consuming

    public AbstractBuilderBufferBuilder(ToStringBuilderType type) {
        super(type);
    }

    public final BlockTree buildToString(final WorkingCopy wc, final String className,
            final BuilderOptions options) {
        final TreeMaker make = wc.getTreeMaker();
        final List<StatementTree> stmts = new ArrayList<StatementTree>();
        stmts.add(make.ExpressionStatement(make.Identifier(this.getType().getClassAsString() +
                " builder = new " + this.getType().getClassAsString() + "()")));
        stmts.add(make.ExpressionStatement(make.Identifier("builder.append(\"" + className + " [\")")));
        boolean first = true;
        for (final Element element : options.getElements()) {
            String prefix;
            if (first) {
                prefix = "builder.append(\"";
                 first = false;
            } else {
                prefix = "builder.append(\", ";
            }

            String statement1 = prefix + element.getSimpleName() + "=\")";
            String statement2 = "";

            if (options.isUseArrayToString() && isArray(element)) {
                addArrayImport(make, wc);
                statement2 = "Arrays.toString(" + element.getSimpleName() + ")";
            } else {
                statement2 = element.getSimpleName() + "" + (isMethod(element) ? "()" : "");
            }

            if(options.isChainAppends() && statement2.length() > 0) {
                statement2 = ".append(" + statement2 + ")";
                stmts.add(make.ExpressionStatement(make.Identifier(statement1 + statement2)));
            } else {
                statement2 = "builder.append(" + statement2 + ")";
                stmts.add(make.ExpressionStatement(make.Identifier(statement1)));
                stmts.add(make.ExpressionStatement(make.Identifier(statement2)));
            }
        }

        stmts.add(make.ExpressionStatement(make.Identifier("builder.append(\"]\")")));
        stmts.add(make.Return(make.Identifier("builder.toString()")));
        final BlockTree body = make.Block(stmts, false);
        return body;
    }
}
